#replication materials for "Illiberal attitudes among US state legislative candidates"
library(lmtest)
library(sandwich)
library(tidyverse)
library(reshape2) 
library(RColorBrewer)

survey <- read.csv("~/Desktop/primary_candidates_survey_replication.csv")
head(survey)

#drop non-candidates
survey <- subset(survey, Q1 == 1)
table(survey$Q1)

#make binary party variable
survey$republican <- ifelse(survey$Q53 == 1, 1, 0)
survey$democrat <- ifelse(survey$Q53 == 2, 1, 0)

#make pid5 variable
survey$pid7 <- ""
survey$pid7[survey$republican == 1 & survey$Q54 == 1] <- "Strong Republican"
survey$pid7[survey$republican == 1 & survey$Q54 == 2] <- "Not so strong Republican"
survey$pid7[survey$democrat == 1 & survey$Q55 == 1] <- "Not so strong Democrat"
survey$pid7[survey$democrat == 1 & survey$Q55 == 2] <- "Strong Democrat"




#Figure 1: election institutions battery
institutions.battery <- subset(survey, select = c("ResponseId", "republican", "democrat", colnames(survey)[startsWith(colnames(survey), "Q51")]))

#make pivot table
mdfr3 <- melt(institutions.battery, id.vars = c("ResponseId", "republican", "democrat"))
mdfr3 <- subset(mdfr3, !is.na(republican))
mdfr3$question.party <- paste(mdfr3$variable, mdfr3$republican, sep = "-")

percentData3 <- mdfr3 %>% filter(!is.na(value)) %>% 
  group_by(variable, republican) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100,
         ratio2 = case_when(ratio < 4.5 ~ "",
                            TRUE ~ paste(as.character(round(ratio, 0)), "%", sep = "")))

percentData3$label <- ""
percentData3$label[percentData3$variable == "Q51_1"] <- "Politicians have a responsibility to challenge election results when they lose."
percentData3$label[percentData3$variable == "Q51_2"] <- "The people should challenge election results even if the official certification deems their party the loser."
percentData3$label[percentData3$variable == "Q51_3"] <- "If my party can change election rules to help win in the future, they should do so."
percentData3$label[percentData3$variable == "Q51_4"] <- "It is important to respect the outcome of elections, even when my party loses."
percentData3$label[percentData3$variable == "Q51_5"] <- "The country would be better off if certain people didn't vote."

percentData3$label <- factor(percentData3$label, levels = c("It is important to respect the outcome of elections, even when my party loses.", "Politicians have a responsibility to challenge election results when they lose.", "The people should challenge election results even if the official certification deems their party the loser.", "If my party can change election rules to help win in the future, they should do so.",  "The country would be better off if certain people didn't vote."))

#save as 10x8 size
ggplot(data = percentData3, aes(x=factor(republican), y = n, fill = factor(value))) + 
  geom_bar(position = "fill", stat = "identity") + 
  geom_text(aes(label = ratio2), position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) +
  facet_wrap(vars(label), labeller = labeller(label = label_wrap_gen(width = 46))) + 
  theme_bw() + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(strip.background = element_rect(fill = "NA")) + 
  labs(x = "", y = "Proportion", title = "To what extent do you agree or disagree with the following statements...") + 
  scale_x_discrete(labels = c("Democrat", "Republican"))

#pooled together
percentData3 <- mdfr3 %>% filter(!is.na(value)) %>% 
  group_by(variable) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100)

percentData3$label <- ""
percentData3$label[percentData3$variable == "Q51_1"] <- "Politicians have a responsibility to challenge election results when they lose."
percentData3$label[percentData3$variable == "Q51_2"] <- "The people should challenge election results even if the official certification deems their party the loser."
percentData3$label[percentData3$variable == "Q51_3"] <- "If my party can change election rules to help win in the future, they should do so."
percentData3$label[percentData3$variable == "Q51_4"] <- "It is important to respect the outcome of elections, even when my party loses."
percentData3$label[percentData3$variable == "Q51_5"] <- "The country would be better off if certain people didn't vote."

percentData3$label <- factor(percentData3$label, levels = rev(c("It is important to respect the outcome of elections, even when my party loses.",
                                                                "Politicians have a responsibility to challenge election results when they lose.", 
                                                                "The people should challenge election results even if the official certification deems their party the loser.", 
                                                                "If my party can change election rules to help win in the future, they should do so.",  
                                                                "The country would be better off if certain people didn't vote.")))

ggplot(data = percentData3, aes(x = label, y = n, fill = factor(value), label = paste(round(ratio, 0), "%", sep = ""))) + 
  geom_bar(stat = "identity", position = "fill") + 
  geom_text(position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) + 
  coord_flip() +
  scale_x_discrete(labels = function(x) str_wrap(x, width = 20)) + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse=TRUE)) + 
  labs(y = "", x = "Proportion", title = "To what extent do you agree or disagree with the following statements...")




#Figure 2: violence battery
violence.battery <- subset(survey, select = c("ResponseId", "republican", "democrat", colnames(survey)[startsWith(colnames(survey), "Q49")]))

#make pivot table
mdfr5 <- melt(violence.battery, id.vars = c("ResponseId", "republican", "democrat"))
mdfr5 <- subset(mdfr5, !is.na(republican))
mdfr5$question.party <- paste(mdfr5$variable, mdfr5$republican, sep = "-")

percentData5 <- mdfr5 %>% filter(!is.na(value)) %>% 
  group_by(variable, republican) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100,
         ratio2 = case_when(ratio < 4.5 ~ "",
                            TRUE ~ paste(as.character(round(ratio, 0)), "%", sep = "")))

percentData5$label <- ""
percentData5$label[percentData5$variable == "Q49_1"] <- "It is sometimes OK for my party to send threatening and intimidating messages to the other party's leaders."
percentData5$label[percentData5$variable == "Q49_2"] <- "It is sometimes justified for my party to use violence in advancing their political goals these days."
percentData5$label[percentData5$variable == "Q49_3"] <- "If the other party has the majority in Congress after the 2022 elections, violence might be justified."
percentData5$label[percentData5$variable == "Q49_4"] <- "If elected leaders will not protect America, the people must do it themselves even if it requires taking violent actions."

percentData5$label <- factor(percentData5$label, levels = c("It is sometimes justified for my party to use violence in advancing their political goals these days.",
                                                            "If the other party has the majority in Congress after the 2022 elections, violence might be justified.", 
                                                            "It is sometimes OK for my party to send threatening and intimidating messages to the other party's leaders.", 
                                                            "If elected leaders will not protect America, the people must do it themselves even if it requires taking violent actions."))

#save as 10x8 size
ggplot(data = percentData5, aes(x=factor(republican), y = n, fill = factor(value))) + 
  geom_bar(position = "fill", stat = "identity") + 
  geom_text(aes(label = ratio2), position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) +
  facet_wrap(vars(label), labeller = labeller(label = label_wrap_gen(width = 55))) + 
  theme_bw() + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(strip.background = element_rect(fill = "NA")) + 
  labs(x = "", y = "Proportion", title = "To what extent do you agree or disagree with the following statements...") + 
  scale_x_discrete(labels = c("Democrat", "Republican"))

#pooled together
percentData5 <- mdfr5 %>% filter(!is.na(value)) %>% 
  group_by(variable) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100)

percentData5$label <- ""
percentData5$label[percentData5$variable == "Q49_1"] <- "It is sometimes OK for my party to send threatening and intimidating messages to the other party's leaders."
percentData5$label[percentData5$variable == "Q49_2"] <- "It is sometimes justified for my party to use violence in advancing their political goals these days."
percentData5$label[percentData5$variable == "Q49_3"] <- "If the other party has the majority in Congress after the 2022 elections, violence might be justified."
percentData5$label[percentData5$variable == "Q49_4"] <- "If elected leaders will not protect America, the people must do it themselves even if it requires taking violent actions."


percentData5$label <- factor(percentData5$label, levels = c("It is sometimes justified for my party to use violence in advancing their political goals these days.",
                                                            "If the other party has the majority in Congress after the 2022 elections, violence might be justified.", 
                                                            "It is sometimes OK for my party to send threatening and intimidating messages to the other party's leaders.", 
                                                            "If elected leaders will not protect America, the people must do it themselves even if it requires taking violent actions."))

ggplot(data = percentData5, aes(x = label, y = n, fill = factor(value), label = paste(round(ratio, 0), "%", sep = ""))) + 
  geom_bar(stat = "identity", position = "fill") + 
  geom_text(position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) + 
  coord_flip() +
  scale_x_discrete(labels = function(x) str_wrap(x, width = 20)) + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse=TRUE)) + 
  labs(x = "", y = "Proportion", title = "To what extent do you agree or disagree with the following statements...")




#Figure 3: Civil Liberties 
news.battery <- subset(survey, select = c("ResponseId", "republican", "democrat", colnames(survey)[startsWith(colnames(survey), "Q52")]))

#make pivot table
mdfr4 <- melt(news.battery, id.vars = c("ResponseId", "republican", "democrat"))
mdfr4 <- subset(mdfr4, !is.na(republican))
mdfr4$question.party <- paste(mdfr4$variable, mdfr4$republican, sep = "-")

percentData4 <- mdfr4 %>% filter(!is.na(value)) %>% 
  group_by(variable, republican) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100,
         ratio2 = case_when(ratio < 4.5 ~ "",
                            TRUE ~ paste(as.character(round(ratio, 0)), "%", sep = "")))

percentData4$label <- ""
percentData4$label[percentData4$variable == "Q52_1"] <- "Negative media coverage of the other party's candidates should be subject to more scrutiny than negative coverage of my party."
percentData4$label[percentData4$variable == "Q52_2"] <- "Newspapers should be limited in the number of critical pieces they can publish about my party's candidates. "
percentData4$label[percentData4$variable == "Q52_3"] <- "Companies should fire employees who post the other party's extreme views on social media."
percentData4$label[percentData4$variable == "Q52_4"] <- "There are too many extreme speakers of the other party invited to speak on college campuses today."
percentData4$label[percentData4$variable == "Q52_5"] <- "Government should monitor people who post the other  party's extreme views online"

#save as 10x8 size
ggplot(data = percentData4, aes(x=factor(republican), y = n, fill = factor(value))) + 
  geom_bar(position = "fill", stat = "identity") + 
  geom_text(aes(label = ratio2), position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) +
  facet_wrap(vars(label), labeller = labeller(label = label_wrap_gen(width = 43))) + 
  theme_bw() + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(strip.background = element_rect(fill = "NA")) + 
  labs(x = "", y = "Proportion", title = "To what extent do you agree or disagree with the following statements...") + 
  scale_x_discrete(labels = c("Democrat", "Republican"))



#pooled together
percentData4 <- mdfr4 %>% filter(!is.na(value)) %>% 
  group_by(variable) %>% 
  count(value) %>%
  mutate(ratio=n/sum(n)*100,
         ratio2 = case_when(ratio < 4.5 ~ "",
                            TRUE ~ paste(as.character(round(ratio, 0)), "%", sep = "")))

percentData4$label <- ""
percentData4$label[percentData4$variable == "Q52_1"] <- "Negative media coverage of the other party's candidates should be subject to more scrutiny than negative coverage of my party."
percentData4$label[percentData4$variable == "Q52_2"] <- "Newspapers should be limited in the number of critical pieces they can publish about my party's candidates."
percentData4$label[percentData4$variable == "Q52_3"] <- "Companies should fire employees who post the other party's extreme views on social media."
percentData4$label[percentData4$variable == "Q52_4"] <- "There are too many extreme speakers of the other party invited to speak on college campuses today."
percentData4$label[percentData4$variable == "Q52_5"] <- "Government should monitor people who post the other  party's extreme views online"


percentData4$label <- factor(percentData4$label, levels = rev(c("There are too many extreme speakers of the other party invited to speak on college campuses today.",
                                                                "Government should monitor people who post the other  party's extreme views online", 
                                                                "Companies should fire employees who post the other party's extreme views on social media.", 
                                                                "Negative media coverage of the other party's candidates should be subject to more scrutiny than negative coverage of my party.",  
                                                                "Newspapers should be limited in the number of critical pieces they can publish about my party's candidates.")))

ggplot(data = percentData4, aes(x = label, y = n, fill = factor(value), label = paste(round(ratio, 0), "%", sep = ""))) + 
  geom_bar(stat = "identity", position = "fill") + 
  geom_text(position = position_fill(vjust = .5), stat = "identity", color = "black", size = 4) + 
  coord_flip() +
  scale_x_discrete(labels = function(x) str_wrap(x, width = 20)) + 
  scale_fill_manual(name = "", labels = c("Strongly Agree", "Agree", "Neither", "Disagree", "Strongly Disagree"), values = rev(c(brewer.pal(5, "RdYlGn")))) + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse=TRUE)) + 
  labs(x = "", y = "Proportion", title = "To what extent do you agree or disagree with the following\nstatements about [respondent's outparty]...")





###################################################
########## REGRESSION MODELS ######################
###################################################
regression <- read.csv("~/Desktop/Barber_Hassell_Miller_NHSCOMMS_replication_regression.csv")

#CONTROL VARIABLES:
#gender Q43
regression$gender <- regression$Q43
regression$gender[regression$gender == 4] <- 3
regression$gender <- factor(regression$gender, levels = c(1, 2, 3), labels = c("Male", "Female", "Other"))

regression$male <- ifelse(regression$Q43 == 1, 1, 0)

#race Q37_1 - Q37_7
regression$white <- ifelse(regression$Q37 == "1", 1, 0)
regression$black <- ifelse(regression$Q37 == "2", 1, 0)
regression$hispanic <- ifelse(regression$Q37 %in% c("3", "1,3"), 1, 0)
regression$other.race <- ifelse(regression$white == 0 & regression$black == 0 & regression$hispanic == 0, 1, 0)

regression$race <- ""
regression$race[regression$white == 1] <- "White"
regression$race[regression$black == 1] <- "Black"
regression$race[regression$hispanic == 1] <- "Hispanic"
regression$race[regression$other.race == 1] <- "Other"
regression$race <- factor(regression$race, levels = c("White", "Black", "Hispanic", "Other"))

#education Q39 [1-5]
table(regression$Q39)
regression$educ <- regression$Q39

#income Q38
regression$income <- regression$Q38
regression$income[regression$income == 9] <- NA
table(regression$income)

#age Q36
regression$age <- regression$Q36 + 17
table(regression$age)

#religion-born again Q41
regression$born.again <- ifelse(regression$Q41 == 1, 1, 0)
table(regression$born.again)

#religiosity 
regression$religious <- abs(regression$Q42-6)
table(regression$religious)

#number of candidates
regression$num.cands <- regression$num_prim_can
table(regression$num.cands)
regression$num.cand[regression$num.cands == 0] <- 1

#multi-member districts 
regression$multi.mem <- regression$mmd
table(regression$multi.mem)

#number of winners
regression$num.winners <- regression$num_winners
table(regression$num_winners)

#won primary
regression$won.primary <- regression$winner
table(regression$won.primary)

#incumbent, challenger, open
regression$incumb <- ifelse(regression$os_incumbency == "INCUMBENT", 1, 0)
regression$challenger <- ifelse(regression$os_incumbency == "CHALLENGER", 1, 0)
regression$open.seat <- ifelse(regression$os_incumbency == "OPEN", 1, 0)
regression$incumb[is.na(regression$incumb)] <- 0

#prior experience
regression$prior.exp <- regression$quality
table(regression$prior.exp)

#candidate money raised
regression$cand.money <- regression$can_raised
summary(regression$cand.money)
regression$cand.money[regression$cand.money < 1] <- 1
summary(regression$cand.money)
regression$cand.money <- log(regression$cand.money)

#district total money raised
regression$dist.money <- regression$total_raised
regression$dist.money[regression$dist.money < 1] <- 1
summary(regression$dist.money)
regression$dist.money <- log(regression$dist.money)

#share of total contributions
regression$share.money <- regression$perc_funds
summary(regression$share.money)

#republican
regression$republican <- ifelse(regression$Q53 == 1, 1, 0)
regression$democrat <- ifelse(regression$Q53 == 2, 1, 0)

#state
regression$state <- substr(regression$state, 1, 2)

#state level party response rate
regression <- regression %>%
  mutate(pty = ifelse(republican == 1, "R", "D")) 

regression <- regression %>%
  mutate(fake.elector.state = ifelse(regression$state %in% c("AZ", "GA", "MI", "NV", "NM", "PA", "WI"), 1, 0),
         swing.state = ifelse(regression$state %in% c("FL", "NC", "GA", "AZ", "WI", "PA", "NV", "MI"), 1, 0))

regression$dist.to.advance[regression$dist.to.advance == -999] <- NA


#1. electoral democracy index

#Q51_1 Politicians have a responsibility to challenge election results when they lose
#Q51_2 The people should challenge election results even if the official certification deems their party the loser
#Q51_3 If my party can change election rules to help win in the future, they should do so
#Q51_4 It is important to respect the outcome of elections, even when my party loses
#Q51_5 The country would be better off if certain people didn't vote

regression$index_electoral <- abs(regression$Q51_1-6) + abs(regression$Q51_2-6) + abs(regression$Q51_3-6) + regression$Q51_4 + abs(regression$Q51_5-6)
summary(regression$index_electoral)
regression$index_electoral <- regression$index_electoral / max(regression$index_electoral, na.rm = T)

summary(model2a <- lm(index_electoral ~ male + other.race + black + hispanic + educ + age + born.again + religious + republican  + won.primary + dist.to.advance + incumb + prior.exp + share.money, data = regression))

coeftest(model2a, vcov = vcovCL, cluster = ~state)

m2.cluster <- coeftest(model2a, vcov = vcovCL, cluster = ~state)


#2. political violence

#Q49_4 if elected leaders will not protect America, the people must do it themselves even if it requires taking violent action
#Q49_3 if the other party has the majority in Congress after the 2022 elections, violence may be justified
#Q49_2 it is sometimes justified for my party to use violence in advancing their poltiical goals these days
#Q49_1 it is sometimes OK for my party to send threatening and intimidating messages to the other party's leaders

regression$index_violence <- abs(regression$Q49_1-6) + abs(regression$Q49_2-6) + abs(regression$Q49_3-6) + abs(regression$Q49_4-6)
summary(regression$index_violence)
regression$index_violence <- regression$index_violence / max(regression$index_violence, na.rm = T)

summary(model3a <- lm(index_violence ~ male + other.race + black + hispanic + educ + age + born.again + religious + republican  + won.primary + dist.to.advance + incumb + prior.exp + share.money, data = regression))

coeftest(model3a, vcov = vcovCL, cluster = ~state)

m3.cluster <- coeftest(model3a, vcov = vcovCL, cluster = ~state)


#3. free speech

#Q52_1 Negative media coverage of the other party's candidates should be subject to more scrutiny than negative coverage of my party
#Q52_2 Newspapers should be limited in the number of critical pieces they can publish about my party's candidates
#Q52_3 Companies should fire employees who post the other party's extreme views on social media.
#Q52_4 There are too many extreme speakers of the other party invited to speak on college campuses today
#Q52_5 Government should monitor people who post the other party's extreme views online

regression$index_speech <- abs(regression$Q52_1-6) + abs(regression$Q52_2-6) + abs(regression$Q52_3-6) + abs(regression$Q52_4-6) + abs(regression$Q52_5 - 6)
summary(regression$index_speech)
regression$index_speech <- regression$index_speech / max(regression$index_speech, na.rm = T)

summary(model4a <- lm(index_speech ~ male + other.race + black + hispanic + educ + age + born.again + religious + republican  + won.primary + dist.to.advance + incumb + prior.exp + share.money, data = regression))

coeftest(model4a, vcov = vcovCL, cluster = ~state)

m4.cluster <- coeftest(model4a, vcov = vcovCL, cluster = ~state)


library(stargazer)

#Table 1
sink("~/Desktop/output.txt")
stargazer(m2.cluster, m3.cluster, m4.cluster, type = "latex", 
          omit.stat = c("F", "adj.rsq", "ser"), font.size = "small",
          column.labels = c("Electoral Democracy", "Political Violence", "Free Speech"),
          table.placement = "t", label = "table:indices", #star.cutoffs = c(0.05),
          dep.var.labels.include = FALSE, dep.var.caption = "", 
          title = c("Predictors of Illiberal Attitudes"),
          covariate.labels = c("Male [0/1]", "Other Race [0/1]", "Black [0/1]", "Hispanic [0/1]", "Education [1-5]", "Age [18-80]", 
                               "Born Again [0/1]", "Religiosity [1-5]", "Republican [0/1]", 
                               "Won Primary [0/1]", "Dist. to Advancement [-1-1]", 
                               "Incumbent [0/1]", "Prior Experience [0/1]", "Fraction of Money [0-1]", "(Intercept)"),
          add.lines = list(c("Obs.", nobs(model2a), nobs(model3a), nobs(model4a)),
                           c("R Squared", round(summary(model2a)$r.squared, 2), 
                             round(summary(model3a)$r.squared, 2),
                             round(summary(model4a)$r.squared, 2))),
          notes.append = FALSE, notes.label = "", notes.align = "l")
sink()

